/**
 * 
 */
package com.qb.mobile.manager;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;

import com.qb.mobile.model.Address;
import com.qb.mobile.model.Email;
import com.qb.mobile.model.InstantMessenger;
import com.qb.mobile.model.Organization;
import com.qb.mobile.model.Phone;
import com.qb.mobile.model.Phonebook;
import com.qb.mobile.model.Photo;

/**
 * @author <a href="mailto:dangcongthanhtrung@gmail.com">dangtrung</a>
 * 
 *         ContactManager.java class
 * 
 */
public class ContactsSystem {

	private ContentResolver contentResolver;
	private List<Phonebook> list;

	public ContactsSystem(Context context, List<Phonebook> list) {
		this.contentResolver = context.getContentResolver();
		this.list = new ArrayList<Phonebook>();
		this.list = list;
	}

	public List<Phonebook> newContactList() {
 		String id;
 		
 		Cursor cur = this.contentResolver.query(ContactsContract.Contacts.CONTENT_URI,
                 null, null, null, null);
 		if (cur.getCount() > 0) {
 			while (cur.moveToNext()) {
 				Phonebook c = new Phonebook();
 				id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
 				c.setId(id);
 				c.setName(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)));
 				if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
 					ArrayList<Phone> list = this.queryAllPhoneNumbersForContact(id);
 					if(list.size() > 0)
 						c.setPhones(this.queryAllPhoneNumbersForContact(id));
 				}
 				c.setEmails(this.queryAllEmailAddressesForContact(id));
 				c.setNotes(this.queryNotesForContact(id));
 				c.setAddresses(this.queryAddressesForContact(id));
 				c.setImAddresses(this.queryInstantMessengerForContact(id));
 				c.setOrganization(this.queryOrganizationForContact(id));
 				c.setPhoto(this.queryPhotoForContact(id));
 				list.add(c);
 			}
 		}
 		return list;
 	}

	/**
	 * 
	 * @param contactId
	 */
	private Photo queryPhotoForContact(String id) {
		Photo photo = null;

		String[] projection = new String[] { Contacts.DISPLAY_NAME,
				Contacts.PHOTO_ID };
		Cursor contact = contentResolver.query(Contacts.CONTENT_URI,
				projection, Contacts._ID + "=?",
				new String[] { id }, null);

		if (contact.moveToFirst()) {
			String photoId = contact.getString(contact
					.getColumnIndexOrThrow(Contacts.PHOTO_ID));
			byte[] bitmapPhoto;
			if (photoId != null) {
				bitmapPhoto = queryContactBitmap(photoId);
				photo = new Photo(bitmapPhoto, photoId);

			} else {
				photo = null;
			}
			contact.close();
		}
		contact.close();
		return photo;
	}

	/**
	 * 
	 * @param photoId
	 * @return
	 */
	private byte[] queryContactBitmap(String photoId) {
		String[] projection = new String[] { CommonDataKinds.Photo.PHOTO };
		Cursor photo = contentResolver.query(Data.CONTENT_URI, projection,
				Data._ID + "=?", new String[] { photoId }, null);
		byte[] photoBlob = null;
		if (photo.moveToFirst()) {
			photoBlob = photo.getBlob(photo
					.getColumnIndexOrThrow(CommonDataKinds.Photo.PHOTO));
		}
		photo.close();
		return photoBlob;
	}

	/**
	 * Phone numbers are stored in their own table and need to be queried
	 * separately. To query the phone number table use the URI stored in the SDK
	 * variable ContactsContract.CommonDataKinds.Phone.CONTENT_URI. Use a WHERE
	 * conditional to get the phone numbers for the specified contact.
	 * 
	 * @param contactId
	 */
	private ArrayList<Phone> queryAllPhoneNumbersForContact(String id) {
 		ArrayList<Phone> phones = new ArrayList<Phone>();
 		
 		Cursor pCur = this.contentResolver.query(
 				ContactsContract.CommonDataKinds.Phone.CONTENT_URI, 
 				null, 
 				ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?", 
 				new String[]{id}, null);
 		while (pCur.moveToNext()) {
 			String phone = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
 			String type = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
 			if(phone != null && phone.length() > 0 )
 				phones.add(new Phone(phone, type));
 		} 
 		pCur.close();
 		return(phones);
 	}
 	
	
	/**
	 * Querying email addresses is similar to phone numbers. A query must be
	 * performed to get email addresses from the database. Query the URI stored
	 * in ContactsContract.CommonDataKinds.Email.CONTENT_URI to query the email
	 * address table.
	 * 
	 * @param contactId
	 */
	private ArrayList<Email> queryAllEmailAddressesForContact(String id) {

		ArrayList<Email> emailList = new ArrayList<Email>();
		String[] projection = new String[] {
				ContactsContract.CommonDataKinds.Email.DATA,
				ContactsContract.CommonDataKinds.Email.TYPE };

		Cursor emails = this.contentResolver.query(
				ContactsContract.CommonDataKinds.Email.CONTENT_URI, projection,
				Data.CONTACT_ID + "=?",
				new String[] { id }, null);

		while (emails.moveToNext()) {
			String email = emails
					.getString(emails
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.DATA));
			String type = String
					.valueOf(emails.getInt(emails
							.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.TYPE)));
			Email mail = new Email(email, type);
			emailList.add(mail);
		}
		emails.close();
		return emailList;
	}

	/**
	 * Android can store multiple postal addresses per contact. Addresses are
	 * also stored in the data table like notes and queried via the URI stored
	 * in ContactsContract.Data.CONTENT_URI
	 * 
	 * @param contactId
	 * @param phonebook
	 * @return Phonebook
	 */
	private ArrayList<Address> queryAddressesForContact(String id) {

		ArrayList<Address> addrList = new ArrayList<Address>();

		String where = ContactsContract.Data.CONTACT_ID + " = ? AND "
				+ ContactsContract.Data.MIMETYPE + " = ?";
		String[] whereParameters = new String[] {
				id,
				ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE };

		Cursor addrCur = this.contentResolver.query(
				ContactsContract.Data.CONTENT_URI, null, where,
				whereParameters, null);
		while (addrCur.moveToNext()) {
			String poBox = addrCur
					.getString(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POBOX));
			String street = addrCur
					.getString(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET));
			String city = addrCur
					.getString(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY));
			String state = addrCur
					.getString(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION));
			String postalCode = addrCur
					.getString(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE));
			String country = addrCur
					.getString(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY));
			String type = addrCur
					.getString(addrCur
							.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.TYPE));
			Address a = new Address(poBox, street, city, state, postalCode,
					country, type);
			addrList.add(a);
		}
		addrCur.close();
		return (addrList);
	}

	/**
	 * The instant messenger query performs just as the notes and address
	 * queries. Important field names for IM related data are stored in
	 * ContactsContract.CommonDataKinds.Im.
	 * 
	 * @param contactId
	 */
	private ArrayList<InstantMessenger> queryInstantMessengerForContact(String id) {
 		ArrayList<InstantMessenger> imList = new ArrayList<InstantMessenger>();
 		String where = ContactsContract.Data.CONTACT_ID + " = ? AND " 
 			+ ContactsContract.Data.MIMETYPE + " = ?"; 
 		String[] whereParameters = new String[]{id, 
 				ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE}; 
 		
 		Cursor imCur = this.contentResolver.query(ContactsContract.Data.CONTENT_URI, 
 				null, where, whereParameters, null); 
 		if (imCur.moveToNext()) { 
 			String imName = imCur.getString(imCur.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA));
 			String imType;
 			imType = imCur.getString(imCur.getColumnIndex(ContactsContract.CommonDataKinds.Im.TYPE));
 			if (imName.length() > 0) {
 				InstantMessenger im = new InstantMessenger(imName, imType);
 				imList.add(im);
 			}
 		} 
 		imCur.close();
 		return(imList);
 	}

	/**
	 * The last part of the contact record to be covered is the Organizations
	 * data. The Android contact record can contain information about
	 * Employment, professional, and social memberships as well as roles and
	 * titles. These records are queried from the URI stored in
	 * ContactsContract.Data.CONTENT_URI. Important field names for the
	 * organization data are stored in
	 * ContactsContract.CommonDataKinds.Organization.
	 * 
	 * @param contactId
	 * @return Organization
	 */
	private Organization queryOrganizationForContact(String id) {
 		Organization org = new Organization();
 		String where = ContactsContract.Data.CONTACT_ID + " = ? AND " 
 			+ ContactsContract.Data.MIMETYPE + " = ?"; 
 		String[] whereParameters = new String[]{id, 
 				ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE}; 
 		
 		Cursor orgCur = this.contentResolver.query(ContactsContract.Data.CONTENT_URI, 
 				null, where, whereParameters, null);
 
 		if (orgCur.moveToFirst()) { 
 			String orgName = orgCur.getString(orgCur.getColumnIndex(
 					ContactsContract.CommonDataKinds.Organization.DATA));
 			String title = orgCur.getString(orgCur.getColumnIndex(
 					ContactsContract.CommonDataKinds.Organization.TITLE));
 			if (orgName.length() > 0) {
 				org.setOrganization(orgName);
 				org.setTitle(title);
 			}
 		} 
 		orgCur.close();
 		return(org);
 	}

	/**
	 * Custom notes can be attached to each contact record. As before these are
	 * stored in a separate table and are related based on the contact ID.
	 * 
	 * @param contactId
	 */
	private ArrayList<String> queryNotesForContact(String id) {
		ArrayList<String> strList = new ArrayList<String>();
		String noteWhere = Data.CONTACT_ID + " = ? AND " + Data.MIMETYPE
				+ " = ?";
		String[] noteWhereParams = new String[] { id,
				CommonDataKinds.Note.CONTENT_ITEM_TYPE };
		Cursor noteCur = contentResolver.query(Data.CONTENT_URI, null,
				noteWhere, noteWhereParams, null);
		if (noteCur.moveToFirst()) {
			String note = noteCur.getString(noteCur
					.getColumnIndex(CommonDataKinds.Note.NOTE));
			strList.add(note);
		}
		noteCur.close();
		return strList;
	}
}
